/*
 * @(#)Tag.java	0.9 09/01/07
 *
 * Copyright 2007 Fabio Gasparetti. All rights reserved.
 */

package org.tabularium.text.nlp;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.tabularium.text.nlp.wordnet.PartOfSpeech;

/**
 * Some of the standard tags used in the Penn Treebank.
 * <ul>
 * <li>FW - foreign word
 * <li>JJ - adjective or numeral, ordinal
 * <li>JJR - adjective, comparative (-er)
 * <li>JJS - adjective, superlative (-est)
 * <li>NN - noun, common, singular or mass, i.e., Casino, humor
 * <li>NNS - noun, common, plural, i.e., facets
 * <li>NNP - noun, proper, singular, i.e., Conchita
 * <li>NNPS - noun, proper, plural, i.e., Americans
 * <li>RB - adverb, i.e., occasionally
 * <li>RBR - adverb, comparative, i.e., further, greater
 * <li>RBS - adverb, superlative, i.e., biggest, earliest
 * <li>VB - verb, base form
 * <li>VBD - verb, past tense (-ed)
 * <li>VBG - verb, present participle or gerund (-ing)
 * <li>VBN - verb, past participle (-ed)
 * <li>VBP - verb, present tense, not 3rd person singular
 * <li>VBZ - verb, present tense, 3rd person singular (-s)
 * </ul>
 * 
 * For the complete list see:
 * <ul>
 * <li>{@link http://www.comp.leeds.ac.uk/amalgam/tagsets/upenn.html}
 * <li>{@link http://www.comp.leeds.ac.uk/amalgam/tagsets/brown.html}
 * </ul>
 * 
 * @author Fabio Gasparetti
 * @version 0.9, 09/01/07
 */
public class Tag implements Comparable {

	/** see PartOfSpeech */
	protected int pos;

	protected String type;

	protected String content;

	protected int length;

	/**
	 * Even though it is a long type, some methods, e.g., compareTo, cast it to
	 * integer.
	 */
	protected long start;

	protected Map features;

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Map getFeatures() {
		return features;
	}

	public void setFeatures(Map features) {
		this.features = features;
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}

	public long getStart() {
		return start;
	}

	public void setStart(long start) {
		this.start = start;
	}

	/**
	 * Returns the string representing the tag type, e.g., SpaceToken, Token,
	 * JobTitle.
	 * 
	 * The vocabulary depends on the particular text tagger.
	 * 
	 * @return
	 */
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	/**
	 * Returns an integer representing the tag part-of-speech, e.g., NOUN,
	 * ADVERB, VERB.
	 * 
	 * See the PartOfSpeech class for the available POSs.
	 */
	public int getPos() {
		return pos;
	}

	public void setPos(int pos) {
		this.pos = pos;
	}

	/**
	 * True if there is any kind of overleap between two tags.
	 * 
	 * @param t1
	 * @return
	 */
	public boolean overlaps(Tag t1) {
		if ((start > t1.start + length) || (start + length <= t1.start))
			return false;
		return true;
	}

	/**
	 * True if the tag is contained or coincide in length with the parameter.
	 * 
	 * @param t1
	 * @return
	 */
	public boolean contains(Tag t1) {
		if (t1.start >= start && t1.start + t1.length <= start + length)
			return true;
		return false;
	}

	/**
	 * Returns the sublist of tags that are contained in the given tag.
	 * 
	 * @param t1
	 * @return
	 */
	public Tag[] getEnclosed(Tag[] tags) {
		ArrayList l1 = new ArrayList();
		for (int i = 0; i < tags.length; i++) {
			if (contains(tags[i]))
				l1.add(tags[i]);
		}
		return (Tag[]) l1.toArray(new Tag[] {});
	}

	/**
	 * Returns the tags that share the same content but assign a different type
	 * to it.
	 * 
	 * @param t1
	 * @return
	 */
	public Tag[] furtherTypes(Tag[] tags) {
		ArrayList l1 = new ArrayList();
		for (int i = 0; i < tags.length; i++) {
			if (tags[i].start == start && tags[i].length == length
					&& tags[i].length > 0)
				l1.add(tags[i]);
		}
		return (Tag[]) l1.toArray(new Tag[] {});
	}

	/**
	 * Returns the tags that immediately follow the current one.
	 * 
	 * @todo better performance if the given list is ordered.
	 * 
	 * @param t1
	 * @return
	 */
	public Tag[] nextTags(Tag[] tags) {
		ArrayList l1 = new ArrayList();
		long idx = start + length;
		for (int i = 0; i < tags.length; i++) {
			if (tags[i].start == i)
				l1.add(tags[i]);
		}
		return (Tag[]) l1.toArray(new Tag[] {});
	}

	public int compareTo(Object arg0) throws ClassCastException {
		if (!(arg0 instanceof Tag))
			throw new ClassCastException();
		if (arg0 == this)
			return 0;
		Tag t = (Tag) arg0;
		int ret;
		ret = (int) (start - t.start);
		if (ret == 0) {
			ret = length - t.length;
			if (ret == 0) {
				ret = type.compareToIgnoreCase(t.type);
			}
		}
		return (int) ret;
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("type:'" + type + "' ");
		sb.append("pos:'" + PartOfSpeech.toString(pos) + "' ");
		sb.append("start:" + start + " ");
		sb.append("length:" + length + " ");
		sb.append("content:'" + content + "' ");
		if (features != null)
			sb.append("features: [" + features.toString() + "]");
		return sb.toString();
	}

	public static void main(String args[]) throws Exception {
		Tag t1 = new Tag();
		Tag t2 = new Tag();
		t1.start = 4;
		t1.length = 1;
		t2.start = 1;
		t2.length = 3;
		System.out.println(t1.overlaps(t2));
		System.out.println(t2.contains(t1));
	}
}
